<script lang='ts' setup>
import { FormInstance, ScrollbarInstance, TableInstance } from 'element-plus';
import Delete from '~icons/ep/Delete'
import Plus from '~icons/ep/Plus'
import { fetchEventSource } from '@microsoft/fetch-event-source'
interface Template {
  id: string,
  groupIds: string[]
}

const templateOptions = ref<Template[]>([])
function loadTemplateOptions() {
  $request.get(`/template/modules`).then((res) => {
    templateOptions.value = res.data as any;
  })
}

onMounted(() => {
  loadTemplateOptions()
  loadDataSourceOptions()
})

const formDataRef  =ref<FormInstance>()
const formData = reactive({
  templateId: ''
})
const rules = reactive({
  templateId: [
    { required: true, message: '请选择模板', trigger: 'change' }
  ]
})

function handleLoadConfig() {
  formDataRef.value?.validate((valid) => {
    if (valid) {
      $request.get(`/config/byTemplate/${formData.templateId}`).then((res) => {
        tempGroupOptions.value = _tempGroupOptions
        Object.assign(config, res.data)
        if (!!config.dataSourceId) {
          loadTableOptions(config.dataSourceId)
        }
      })
    }
  })
}

let _tempGroupOptions: string[] = [];
let tempGroupOptions = ref<string[]>([]);
function handleChange(val: string) {
  const _temp = templateOptions.value.filter(item => item.id === val);
  _tempGroupOptions = _temp.length === 1 ? _temp[0].groupIds : [];
}
enum GenerateCodeTab {
  GENERATE_CODE,
  TEMPLATE_PARAMS
}
const activeName  = ref<GenerateCodeTab>(GenerateCodeTab.GENERATE_CODE)
const config = reactive({
  id: -1,
  templateGroupId: '',
  dataSourceId: null as number | null,
  rootDir: '',
  tableName: '',
  params: [] as {
    configId: number
    paramName: string
    paramType: string
    paramValue: string
    system: boolean
  }[]
})
const configRules = reactive({
  templateGroupId: [
    { required: true, message: '请选择模板组' }
  ],
  dataSourceId: [
    { required: true, message: '请选择数据源'}
  ],
  rootDir: [
    { required: true, message: '请选择生成目录'}
  ]
})

interface DataSource {
  id: number
  name: string
}
const dataSourceOptions = ref<DataSource[]>([])
function loadDataSourceOptions():void {
  $request.get('/dataSource/list').then(res => {
    dataSourceOptions.value = res.data
  })
}

interface Table {
  tableName: string
  comment: string
}

const tableOptions = ref<Table[]>([])
function loadTableOptions(dataSourceId: number):void {
  $request.get(`/dataSource/table/${dataSourceId}`).then(res => {
    tableOptions.value = res.data
  })
}

function onChangeDataSourceId(dataSourceId: number) {
  config.tableName = ''
  tableOptions.value = []
  loadTableOptions(dataSourceId)
}


const paramsTableRef = ref<TableInstance>()
function handleDeleteVariable(index: number) {
  config.params.splice(index, 1)
}
function handleAddVariable() {
  config.params.push({
    paramName: '',
    paramValue: '',
    paramType: 'STRING',
    system: false,
    configId: config.id
  })
  nextTick(() => {
    const el = document.querySelector('.params-table .el-scrollbar__view')
    paramsTableRef.value?.scrollTo({
      top: el?.clientHeight,
      behavior: 'smooth'
    })
  })
}

const configFormDataRef = ref<FormInstance>()

const errorParamsCount = ref(0)
const errorGenerateCount = ref(0)
const messageList = ref<{ state: 'SUCCESS' | 'ERROR', message: string, fileName: string, outputDir: string }[]>([])

const innerRef = ref<HTMLDivElement>()
const scrollbarRef = ref<ScrollbarInstance>()
// 控制滚动条滚动到容器的底部
async function scrollToBottom() {
  await nextTick()
  const max = innerRef.value?.clientHeight
  scrollbarRef.value?.setScrollTop(max!)
}
function handleGenerateFile() {
  errorParamsCount.value  = 0;
  errorGenerateCount.value  = 0;
  configFormDataRef.value?.validate(async (valid, invalidFields) => {
    if (valid) {
      // 保存配置文件
      await $request.post('/config', {...config})
      fetchEventSource('/api/v1.1/template/generateFile/see', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          configId: config.id,
          templateGroupId: config.templateGroupId,
          tableName: config.tableName
        }),
        onmessage: (msg) => {
          const data = JSON.parse(msg.data);
          messageList.value?.push(data)
          scrollToBottom();
        },
      })

    } else {
      const totalError = Object.keys(invalidFields || {});
      const totalErrorCount = totalError.length;
      errorParamsCount.value = totalError.filter(item => {
        return !['templateGroupId', 'dataSourceId','rootDir', 'tableName'].includes(item)
      }).length
      errorGenerateCount.value = totalErrorCount - errorParamsCount.value
    }
  })
}
</script>

<template >
  <div>
    <div>
      <el-form
        :model="formData"
        :rules="rules"
        ref="formDataRef"
        label-width="100px"
        @submit.prevent
        inline
      >
        <el-form-item label="模板配置ID" prop="templateId" >
          <el-select style="width: 250px;" @change="handleChange"  placeholder="模板配置ID" v-model="formData.templateId">
            <el-option :value="item.id" :label="item.id" v-for="item in templateOptions"
            :key="item.id"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleLoadConfig">加载配置</el-button>
          <el-button type="success" @click="handleGenerateFile">生成文件</el-button>
        </el-form-item>
      </el-form>
    </div>
    <el-tabs
      v-model="activeName"
      type="border-card"
    >
      <el-form :model="config" ref="configFormDataRef" label-width="80px" :rules="configRules" >
        <el-tab-pane label="文件生成配置" :name="GenerateCodeTab.GENERATE_CODE">
          <template #label>
            <el-badge v-if="errorGenerateCount>0" :value="errorGenerateCount" class="error-config-count">文件生成配置</el-badge>
            <template v-else>文件生成配置</template>
          </template>
          <el-form-item prop="templateGroupId" label="模板组" >
              <el-select
              filterable placeholder="请选择模板组" v-model="config.templateGroupId">
                <el-option :value="item" :label="item" v-for="item in tempGroupOptions"
                :key="item"></el-option>
              </el-select>
            </el-form-item>
          <el-form-item prop="dataSourceId" label="数据源">
            <el-select
            filterable
            @change="onChangeDataSourceId"
            v-model="config.dataSourceId!" placeholder="请选择数据源">
              <el-option
                v-for="item in dataSourceOptions"
                :key="item.id"
                :label="item.name"
                :value="item.id"
              ></el-option>
            </el-select>
          </el-form-item>
          <el-form-item prop="rootDir" label="输出目录">
            <select-file-path v-model="config.rootDir" />
          </el-form-item>
          <el-form-item prop="tableName" label="数据表">
            <el-select
            filterable
            v-model="config.tableName" placeholder="请选择数据表">
              <el-option
                v-for="item in tableOptions"
                :key="item.tableName"
                :label="`${item.tableName} - (${item.comment})`"
                :value="item.tableName"
              ></el-option>
            </el-select>
          </el-form-item>
        </el-tab-pane>
        <el-tab-pane class="template-params-config" label="模板参数配置" :name="GenerateCodeTab.TEMPLATE_PARAMS">
          <template #label>
            <el-badge v-if="errorParamsCount>0" :value="errorParamsCount" class="error-config-count">模板参数配置</el-badge>
            <template v-else>模板参数配置</template>
          </template>
          <el-table ref="paramsTableRef" class="params-table" height="75vh" highlight-current-row :data="config.params" border style="width: 100%">
            <el-table-column prop="paramName" label="参数名">
              <template #default="{ $index, row }">
                <el-form-item label-width="0px" :rules="[{ required: true, message: '请输入参数名' }]" :prop="`params.${$index}.paramName`" >
                  <el-input :title="row.paramName" :disabled="row.system" v-model="row.paramName" placeholder="请输入参数名" />
                </el-form-item>
              </template>
            </el-table-column>

            <el-table-column prop="paramValue" label="参数值">
              <template #default="{ $index, row }">
                <el-form-item label-width="0px" :rules="[{ required: true, message: '请输入参数值'  }]" :prop="`params.${$index}.paramValue`" >
                <el-input v-model="row.paramValue" placeholder="请输入参数值" />
                </el-form-item>
              </template>
            </el-table-column>

            <el-table-column label="操作"  width="100">
              <template #default="{ $index, row }">
                <div style="display: flex; justify-content: center;">
                    <el-button
                    type="danger"
                    :icon="Delete"
                    link
                    circle
                    :disabled="row.system"
                    @click="handleDeleteVariable($index)"
                  />
                </div>
              </template>
            </el-table-column>
          </el-table>
          <div class="operation">
            <el-button @click="handleAddVariable" type="primary" link :icon="Plus"></el-button>
          </div>
        </el-tab-pane>
      </el-form>
    </el-tabs>
    <el-scrollbar v-if="activeName == GenerateCodeTab.GENERATE_CODE" ref="scrollbarRef" height="280px" class="message-scroll-bar">
      <div ref="innerRef" class="message-wrapper">
        <div v-for="message in messageList" class="message">
          <el-text :type="message.state == 'SUCCESS' ? 'success' : 'danger'">{{ message.fileName }}</el-text>
          ==> <el-text>{{ message.outputDir }}</el-text>
        </div>
      </div>
    </el-scrollbar>
  </div>
</template>

<style scoped lang='less'>
:deep(.el-form) {
  .el-form-item__label {
    font-size: 12px;
  }
}
.message-scroll-bar {
    width: 100%;
    height: 280px;
    margin-top: 20px;
    border: 1px solid #eee;
    user-select: text;
    border-radius: 4px;
    padding: 5px 10px;
    .message {
      white-space: pre-wrap;
      font-size: 10px;
      font-family: monospace;
      margin-bottom: 10px;
    }
  }
.template-params-config {
  position: relative;
  .params-table {
    :deep(.el-form-item) {
      margin: 0px;
    }
  }
  .operation {
    position: absolute;
    top: 7px;
    right: 40px;
    z-index: 9999;
  }
}
</style>
